<?php

/**
 * @file
 * Contains \Drupal\gdlisnet\Plugin\Search\CollectionSearch.
 */

namespace Drupal\gdlisnet\Plugin\Search;

use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\Config;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Render\RendererInterface;
use Drupal\search\Plugin\ConfigurableSearchPluginBase;
use Drupal\search\Plugin\SearchIndexingInterface;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\Url;
use Drupal\Search\SearchQuery;
use Drupal\gdlisnet\Entity\CollectionStorage;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Handles searching for gdlisnet collections using the Search module index.
 *
 * @SearchPlugin(
 *   id = "collection_search",
 *   title = @Translation("Collections")
 * )
 */
class CollectionSearch extends ConfigurableSearchPluginBase implements AccessibleInterface, SearchIndexingInterface {

	/**
	* {@inheritdoc}
	*/
	public function indexClear() {
		// All CollectionSearch pages share a common search index "type" equal to
		// the plugin ID.
		search_index_clear($this->getPluginId());
	}

	/**
	* {@inheritdoc}
	*/
	public function isSearchExecutable() {
		return !empty($this->keywords);
	}

	/**
	* {@inheritdoc}
	*/
	public function indexStatus() {
		try {
			$gdlisnet_database = \Drupal::config('gdlisnet.datasource');
			$conn=oci_connect($gdlisnet_database->get('username'), $gdlisnet_database->get('password'),
				sprintf("%s:%s/%s", $gdlisnet_database->get('host'), $gdlisnet_database->get('port'), $gdlisnet_database->get('database')), 'AL32UTF8'
			);
			if(!$conn) {
				$e=oci_error();
				throw new \Exception($e['message'], $e['code']);
			}
			
			$sql="SELECT COUNT(*) from 馆藏书目库 WHERE EXISTS(SELECT * FROM 书目数据库定义 ".
				"WHERE 馆藏书目库.库键码=书目数据库定义.库键码 AND 书目数据库定义.状态='正常' AND 书目数据库定义.不发布=0)";
			$stmt = @oci_parse($conn, $sql);
			if(!$stmt) {
				$e=oci_error($stmt);
				throw new \Exception($e['message'], $e['code']);
			}

			$r=@oci_execute($stmt, OCI_DEFAULT);
			if(!$r) {
				$e=oci_error($stmt);
				throw new \Exception($e['message'], $e['code']);
			}
			$row=oci_fetch_array($stmt, OCI_NUM);
			$total=$row[0];
		} catch (\Exception $e) {
		} finally {
			if(!empty($stmt))
				oci_free_statement($stmt);
			if(!empty($conn))
				oci_close($conn);
		}
		
		$indexed = Database::getConnection('default')->query("SELECT COUNT(DISTINCT sd.sid) FROM {search_dataset} sd WHERE sd.type=:type",
			[':type' => $this->getPluginId()])->fetchField();

		return ['remaining'=>$total-$indexed, 'total'=>$total];
	}

	/**
	* {@inheritdoc}
	*/
	public function markForReindex() {
		// All CollectionSearch pages share a common search index "type" equal to
		// the plugin ID.
		search_mark_for_reindex($this->getPluginId());
	}

	/**
	* {@inheritdoc}
	*/
	public function updateIndex() {
		$limit = (int) \Drupal::config('search.settings')->get('index.cron_limit');
		
		try {
			$gdlisnet_database = \Drupal::config('gdlisnet.datasource');
			$conn=oci_connect($gdlisnet_database->get('username'), $gdlisnet_database->get('password'),
				sprintf("%s:%s/%s", $gdlisnet_database->get('host'), $gdlisnet_database->get('port'), $gdlisnet_database->get('database')), 'AL32UTF8'
			);
			if(!$conn) {
				$e=oci_error();
				throw new \Exception($e['message'], $e['code']);
			}
			
			$sql=sprintf("SELECT 主键码 FROM 检索一对多库_日志 WHERE ROWNUM<=%s ORDER BY 时间戳 ASC ", $limit);
			$stmt = @oci_parse($conn, $sql);
			if(!$stmt) {
				$e=oci_error($stmt);
				throw new \Exception($e['message'], $e['code']);
			}

			$r=@oci_execute($stmt, OCI_DEFAULT);
			if(!$r) {
				$e=oci_error($stmt);
				throw new \Exception($e['message'], $e['code']);
			}

			$collections=[];
			oci_fetch_all($stmt, $collections);
			foreach($collections['主键码'] as $collection) {
				search_index_clear($this->getPluginId(), $collection);
				$sql=sprintf('SELECT WM_CONCAT(TO_CHAR(数据)) FROM 检索一对多库 WHERE 主键码=%s', $collection);
				$stmt = @oci_parse($conn, $sql);
				if(!$stmt) {
					$e=oci_error($stmt);
					throw new \Exception($e['message'], $e['code']);
				}

				$r=@oci_execute($stmt, OCI_DEFAULT);
				if(!$r) {
					$e=oci_error($stmt);
					throw new \Exception($e['message'], $e['code']);
				}

				$keywords=oci_fetch_array($stmt);
				if(!empty($keywords)) {
					search_index($this->getPluginId(), $collection, 'zh-hans', $keywords[0]);
					$book=$collection=\Drupal::entityManager()->getStorage('collection')->load($collection);
					$retrivalNo=$book->get['索书号'];
					db_merge('search_index')
						->keys(array(
							'word' => $retrievalNo,
							'sid' => $collection,
							'langcode' => 'zh-hans',
							'type' => $this->getPluginId(),
						))
						->fields(array('score' => 1))
						->expression('score', 'score + :score', array(':score' => 1))
					->execute();
				}

				$sql=sprintf('DELETE FROM 检索一对多库_日志 WHERE 主键码=%s', $collection);
				$stmt = @oci_parse($conn, $sql);
				if(!$stmt) {
					$e=oci_error($stmt);
					throw new \Exception($e['message'], $e['code']);
				}

				$r=@oci_execute($stmt, OCI_DEFAULT);
				if(!$r) {
					$e=oci_error($stmt);
					throw new \Exception($e['message'], $e['code']);
				}
				
			}
		} catch (\Exception $e) {
		} finally {
			if(!empty($conn))
				oci_commit($conn);
			if(!empty($stmt))
				oci_free_statement($stmt);
			if(!empty($conn))
				oci_close($conn);
		}
	}

	/**
	* {@inheritdoc}
	*/
	public function execute() {
		if ($this->isSearchExecutable()) {
			$results = $this->findResults();

			if ($results)
				return $this->prepareResults($results);
		}
		return array();
	}
	
	/**
	* Queries to find search results, and sets status messages.
	*
	* This method can assume that $this->isSearchExecutable() has already been
	* checked and returned TRUE.
	*
	* @return \Drupal\Core\Database\StatementInterface|null
	*   Results from search query execute() method, or NULL if the search
	*   failed.
	*/
	protected function findResults() {
		// Build matching conditions.
		$query = Database::getConnection('default')
			->select('search_index', 'i', array('target' => 'replica'))
			->extend('Drupal\search\SearchQuery')
			->extend('Drupal\Core\Database\Query\PagerSelectExtender');
		$query->searchExpression($this->keywords, $this->getPluginId());
		$find = $query->limit(10)->execute();
		return $find;
	}

	/**
	* Prepares search results for rendering.
	*
	* @param \Drupal\Core\Database\StatementInterface $found
	*   Results found from a successful search query execute() method.
	*
	* @return array
	*   Array of search result item render arrays (empty array if no results).
	*/
	protected function prepareResults(StatementInterface $found) {
		$results = array();
		foreach($found as $item) {
			$collection=\Drupal::entityManager()->getStorage('collection')->load($item->sid);
			if($collection) {
				$results[] = [
					'link' => Url::fromRoute('gdlisnet.collection.entity', ['collection'=>$item->sid])->toString(),
					'title' => search_excerpt($this->keywords, $collection->get('题名2')),
					'extra' => [
						search_excerpt($this->keywords, $collection->get('责任者')),
						search_excerpt($this->keywords, $collection->get('出版者').' '.$collection->get('出版日期'))
					],
					'score' => $item->calculated_score,
				];
			}
		}
		return $results;
	}

	/**
	* {@inheritdoc}
	*/
	public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
		$form['test']=['#markup'=>'test'];
		return $form;
	}

	/**
	* {@inheritdoc}
	*/
	public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
		return [];
	}
	
	/**
	* {@inheritdoc}
	*/
	public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
		$result=new AccessResultAllowed();
		return $return_as_object ? $result : $result->isAllowed();;
	}

	/**
	* {@inheritdoc}
	*/
	public function getHelp() {
		// This default search help is appropriate for plugins like NodeSearch
		// that use the SearchQuery class.
		$help = ['list' => [
			'#theme' => 'item_list',
			'#items' => [
				$this->t('Please input the keyword to search. For example, the title, author, publisher or the ISBN number.'),
			],
		]];

		return $help;
	}

	/**
	* {@inheritdoc}
	*/
	public function searchFormAlter(array &$form, FormStateInterface $form_state) {
		$form['basic']['keys']['#size']=100;
	}

}
?>
